﻿namespace ReplayDataFile
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;

    public class DataTypeDirectory
    {
        private List<DataTypeDirEntry> dirEntries;
        private Dictionary<int, DataTypeDirEntry> entryDict = new Dictionary<int, DataTypeDirEntry>();
        private int maxDataTypes = 0;

        public DataTypeDirectory(int maxDataTypes, ICollection<DataTypeInfo> dataTypes)
        {
            this.maxDataTypes = maxDataTypes;
            if (dataTypes == null)
            {
                this.dirEntries = new List<DataTypeDirEntry>();
            }
            else if (dataTypes.Count > maxDataTypes)
            {
                Debug.Assert(false, "最大数据类型数目应大于等于当前数据类型数目！");
            }
            else
            {
                this.Init(dataTypes);
            }
        }

        public bool AddDataType(DataTypeInfo dataType)
        {
            if (this.GetDirEntry(dataType.DataType) != null)
            {
                return false;
            }
            if (this.dirEntries.Count >= this.maxDataTypes)
            {
                return false;
            }
            DataTypeDirEntry item = new DataTypeDirEntry();
            this.dirEntries.Add(item);
            item.DataType = dataType.DataType;
            item.IsWriteIndex = dataType.HasIndex;
            item.Name = dataType.Name;
            this.entryDict.Add(item.DataType, item);
            return true;
        }

        public bool FromByteBuffer(byte[] buf)
        {
            try
            {
                BinaryReader reader = new BinaryReader(new MemoryStream(buf));
                int num = reader.ReadInt32();
                int num2 = reader.ReadInt32();
                reader.ReadBytes(0x38);
                this.maxDataTypes = (num - 0x40) / DataTypeDirEntry.Size;
                num2 = Math.Min(num2, this.maxDataTypes);
                this.entryDict.Clear();
                this.dirEntries = new List<DataTypeDirEntry>();
                for (int i = 0; i < num2; i++)
                {
                    DataTypeDirEntry item = new DataTypeDirEntry {
                        DataType = reader.ReadInt32(),
                        Name = this.ToName(reader.ReadBytes(0x80)),
                        FirstDataBlock = reader.ReadInt32(),
                        DataBlockOffset = reader.ReadInt32(),
                        FirstIndexBlock = reader.ReadInt32(),
                        IndexBlockOffset = reader.ReadInt32(),
                        DataRecordCount = reader.ReadInt32(),
                        IndexRecordCount = reader.ReadInt32(),
                        DataRecordTotalBytes = reader.ReadInt64(),
                        DataFormat = reader.ReadByte(),
                        IsWriteIndex = reader.ReadByte() == 1
                    };
                    reader.ReadBytes(90);
                    if (!this.entryDict.ContainsKey(item.DataType))
                    {
                        this.dirEntries.Add(item);
                        this.entryDict.Add(item.DataType, item);
                    }
                    else
                    {
                        Trace.WriteLine(string.Format("数据类型重复0X{0:X} ({0})！", item.DataType));
                    }
                }
                reader.Close();
                return true;
            }
            catch (Exception exception)
            {
                Trace.WriteLine(string.Format("DataTypeDir::FromByteBuffer(byte[] buf) error!: {0}！", exception.Message));
                return false;
            }
        }

        public DataTypeInfo[] GetDataTypes()
        {
            if (this.dirEntries == null)
            {
                return new DataTypeInfo[0];
            }
            DataTypeInfo[] infoArray = new DataTypeInfo[this.dirEntries.Count];
            for (int i = 0; i < this.dirEntries.Count; i++)
            {
                infoArray[i] = new DataTypeInfo();
                infoArray[i].DataType = this.dirEntries[i].DataType;
                infoArray[i].Name = this.dirEntries[i].Name;
                infoArray[i].HasIndex = this.dirEntries[i].IsWriteIndex;
            }
            return infoArray;
        }

        public DataTypeDirEntry GetDirEntry(int dataType)
        {
            if (this.entryDict.ContainsKey(dataType))
            {
                return this.entryDict[dataType];
            }
            return null;
        }

        public DataTypeDirEntry GetDirEntry(string dataTypeName)
        {
            foreach (DataTypeDirEntry entry in this.dirEntries)
            {
                if (entry.Name == dataTypeName)
                {
                    return entry;
                }
            }
            return null;
        }

        public List<DataTypeDirEntry> GetDirEntryList(int dataType)
        {
            if ((dataType & 0xffff) == 0xffff)
            {
                List<DataTypeDirEntry> list = new List<DataTypeDirEntry>();
                foreach (DataTypeDirEntry entry in this.dirEntries)
                {
                    if ((entry.DataType >> 0x10) == (dataType >> 0x10))
                    {
                        list.Add(entry);
                    }
                }
                return list;
            }
            if (this.entryDict.ContainsKey(dataType))
            {
                return new List<DataTypeDirEntry> { this.entryDict[dataType] };
            }
            return null;
        }

        private byte[] GetNameBuffer(DataTypeDirEntry entry)
        {
            byte[] buffer = new byte[0x80];
            if (!string.IsNullOrEmpty(entry.Name))
            {
                BinaryWriter writer = new BinaryWriter(new MemoryStream(buffer));
                char[] chars = entry.Name.ToCharArray();
                int num = (chars.Length <= 0x3e) ? chars.Length : 0x3e;
                writer.Write(num);
                writer.Write(chars);
            }
            return buffer;
        }

        public void Init(ICollection<DataTypeInfo> dataTypes)
        {
            if (dataTypes == null)
            {
                foreach (DataTypeDirEntry entry in this.DirEntries)
                {
                    entry.Init();
                }
            }
            else
            {
                this.dirEntries = new List<DataTypeDirEntry>();
                foreach (DataTypeInfo info in dataTypes)
                {
                    this.AddDataType(info);
                }
            }
        }

        public bool RemoveDataType(int dataType)
        {
            DataTypeDirEntry dirEntry = this.GetDirEntry(dataType);
            if (dirEntry == null)
            {
                return false;
            }
            this.dirEntries.Remove(dirEntry);
            this.entryDict.Remove(dirEntry.DataType);
            return true;
        }

        public byte[] ToByteBuffer()
        {
            byte[] buffer = new byte[this.Size];
            BinaryWriter writer = new BinaryWriter(new MemoryStream(buffer));
            writer.Write(buffer.Length);
            writer.Write(this.dirEntries.Count);
            writer.Write(new byte[0x38]);
            foreach (DataTypeDirEntry entry in this.dirEntries)
            {
                writer.Write(entry.DataType);
                writer.Write(this.GetNameBuffer(entry));
                writer.Write(entry.FirstDataBlock);
                writer.Write(entry.DataBlockOffset);
                writer.Write(entry.FirstIndexBlock);
                writer.Write(entry.IndexBlockOffset);
                writer.Write(entry.DataRecordCount);
                writer.Write(entry.IndexRecordCount);
                writer.Write(entry.DataRecordTotalBytes);
                writer.Write(entry.DataFormat);
                writer.Write(entry.IsWriteIndex ? ((byte) 1) : ((byte) 0));
                writer.Write(new byte[90]);
            }
            return buffer;
        }

        private string ToName(byte[] buf)
        {
            try
            {
                BinaryReader reader = new BinaryReader(new MemoryStream(buf));
                int count = reader.ReadInt32();
                if (count > 0x3e)
                {
                    return "";
                }
                return ((count > 0) ? new string(reader.ReadChars(count)) : "");
            }
            catch (Exception exception)
            {
                Trace.WriteLine(exception.Message);
                return "";
            }
        }

        public List<DataTypeDirEntry> DirEntries
        {
            get
            {
                return this.dirEntries;
            }
        }

        public int MaxDataTypes
        {
            get
            {
                return this.maxDataTypes;
            }
        }

        public int Size
        {
            get
            {
                int num = 8 + (this.maxDataTypes * DataTypeDirEntry.Size);
                return (((num + 0x3ff) / 0x400) * 0x400);
            }
        }
    }
}

